﻿using System;
using System.IO;
using System.Linq;
using System.Configuration;
using System.Collections.Generic;
using System.Text;

namespace CommonLib.Log
{
    public class Logger
    {
        private static Logger instance;
        private static object lockObj = new object();
        private static object writeLockObj = new object();
        private static string logPath = string.Empty;

        private Logger()
        {
            if (ConfigurationManager.AppSettings["CommonLog"] != null)
            {
                logPath = ConfigurationManager.AppSettings["CommonLog"].ToString();
            }
        }

        public static Logger getInstance()
        {
            if (instance == null)
            {
                lock (lockObj)
                {
                    if (instance == null)
                    {
                        instance = new Logger();
                    }
                }
            }

            return instance;
        }

        public List<string> ReadFromLog(int type, string FatherLogPath)
        {
            List<string> retList = new List<string>();

            string path = "{0}\\{1}{2}.txt";
            path = string.Format(path, FatherLogPath, DateTime.Now.ToString("yyyy-MM-dd"), GetLogTypeFileSort(type));
            string line = string.Empty;
            FileInfo myFileInfo = new FileInfo(path);
            if (myFileInfo.Exists)
            {
                long SizeByte = myFileInfo.Length;
                if (SizeByte > (3 * 1024 * 1024))//jpp.LookLogSize
                {
                    retList.Add("日志文件太大，文件在【" + path + "】路径下！");
                }
                else
                {
                    StreamReader sr = new StreamReader(path, Encoding.UTF8);
                    while ((line = sr.ReadLine()) != null)
                    {
                        retList.Add(line);
                    }
                }
            }
            else
            {
                retList.Add("暂无日志！");
            }

            return retList;
        }

        public void WriteToLog(int type, string content, string fatherLogPath)
        {
            string fileName = DateTime.Now.ToString("yyyy-MM-dd") + GetLogTypeFileSort(type);

            WriteToLog(fileName, content, fatherLogPath, true);
        }

        /// <summary>
        /// 写文本日志
        /// </summary>
        /// <param name="fileName">日志文件名称</param>
        /// <param name="content">日志内容</param>
        /// <param name="fatherLogPath">路径地址</param>
        /// <param name="prefixTime">日志内容前是否需要添加时间</param>
        public void WriteToLog(string fileName, string content, string fatherLogPath, bool prefixTime)
        {
            lock (writeLockObj)
            {
                try
                {
                    if (!Directory.Exists(fatherLogPath))//判断路径是否存在，若不存在则创建。
                    {
                        Directory.CreateDirectory(fatherLogPath);//创建新路径
                    }

                    string time = string.Empty;
                    if (prefixTime) time = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss.fff] ");
                    content = time + content + Environment.NewLine;

                    string path = "{0}\\{1}.txt";
                    path = string.Format(path, fatherLogPath, fileName);

                    using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write))
                    {
                        char[] charDataValue = content.ToCharArray();
                        System.Text.Encoder ec = System.Text.Encoding.UTF8.GetEncoder();
                        int byteCount = ec.GetByteCount(charDataValue, 0, charDataValue.Length, true);
                        byte[] byteDataValue = new byte[byteCount];
                        ec.GetBytes(charDataValue, 0, charDataValue.Length, byteDataValue, 0, true);
                        fs.Write(byteDataValue, 0, byteDataValue.Length);
                    }
                }
                catch (Exception ex)
                {
                    Logger.getInstance().WriteToLog((int)LogType.E, "WriteToLog => [{0}][{1}]".FormatWith(content, ex.Message), fatherLogPath);
                }
            }
        }

        /// <summary>
        /// 在保存的日志目录下，复制文本文件到新的文件夹下
        /// </summary>
        /// <param name="sourcePath">原文件路径地址</param>
        /// <param name="sourceFileName">原文件名称</param>
        /// <param name="targetPath">目标文件路径地址</param>
        /// <param name="newFileName">新文件名称</param>
        public void CopyLogToFile(string sourcePath, string sourceFileName, string targetPath, string targetFileName)
        {
            if (!Directory.Exists(sourcePath))
            {
                Directory.CreateDirectory(sourcePath);
            }

            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }

            File.Copy(sourcePath + "\\" + sourceFileName, targetPath + "\\" + targetFileName, true);
        }

        /// <summary>
        /// 根据 日志类型 为文本日志分类
        /// </summary>
        /// <param name="logType">日志类型</param>
        /// <returns></returns>
        public string GetLogTypeFileSort(int logType)
        {
            string fileSort = "Info";
            switch (logType)
            {
                case (int)LogType.E: //错误 日志
                    fileSort = "Error";
                    break;
                case (int)LogType.SQL: //执行SQL语句
                    fileSort = "SQL";
                    break;
                default: 
                    fileSort = "Info";   
                    break;
            }
            return fileSort;
        }

        //public static void LogMsg(string msg)
        //{
        //    if (ConfigurationManager.AppSettings.AllKeys.Contains("SocketLog"))
        //    {
        //        Logger.getInstance().WriteToLog((int)LogType.I, msg, ConfigurationManager.AppSettings["SocketLog"]);
        //    }
        //}

        #region 文本日志清理，包括空文件夹的清理

        /// <summary>
        /// 文本日志 清理
        /// </summary>
        /// <param name="saveDay">保留多少天</param>
        /// <param name="LogPath">日志保存路径</param>
        public void TxtLogClear(int saveDay, string logPath)
        {
            if (Directory.Exists(logPath))//判断路径是否存在，存在，则进行清理
            {
                #region 删除 日志文件

                List<FileInfo> lstFileInfo = GetDirFileList(logPath, "*.txt");
                DateTime maxSaveDT = DateTime.Now.AddDays(-saveDay);

                foreach (FileInfo file in lstFileInfo)
                {
                    string fullName = file.FullName;
                    if (file.CreationTime < maxSaveDT)//文件的创建时间 小于 最大保存时间，则删除文件
                    {
                        File.Delete(fullName);
                    }
                }

                #endregion

                #region 删除空文件夹

                DelEmptyFileFolder(logPath);

                #endregion
            }
        }

        /// <summary>
        /// 文本日志及空文件夹 清理
        /// </summary>
        /// <param name="DTNow">当前时间</param>
        /// <param name="saveDay">保留多少天</param>
        /// <param name="LogPath">日志保存路径</param>
        public void TxtLogFolderClear(DateTime DTNow, int saveDay, string logPath)
        {
            if (Directory.Exists(logPath))//判断路径是否存在，存在，则进行清理
            {
                DirectoryInfo folder = new DirectoryInfo(logPath);
                DirectoryInfo[] dirInfo = folder.GetDirectories();

                #region 清理路径文件下符合格式的文件
                FileInfo[] arrFileInfo = folder.GetFiles("*.txt");
                DateTime maxSaveDT = Convert.ToDateTime(DTNow.AddDays(-saveDay).ToShortDateString() + " 00:00:00");
                foreach (FileInfo file in arrFileInfo)
                {
                    string fullName = file.FullName;
                    if (file.CreationTime < maxSaveDT)//文件的创建时间 小于 最大保存时间，则删除文件
                    {
                        File.Delete(fullName);
                    }
                }
                #endregion

                int fileCount = 0, dirCount = 0;
                for (int i = 0; i < dirInfo.Length; i++)
                {
                    TxtLogFolderClear(DTNow, saveDay, dirInfo[i].FullName);

                    fileCount = dirInfo[i].GetFiles().Length;
                    dirCount = dirInfo[i].GetDirectories().Length;

                    if (fileCount == 0 && dirCount == 0)//目录下即没有文件也没有子目录，则删除文件夹
                    {
                        Directory.Delete(dirInfo[i].FullName, true);
                    }
                }
            }
        }

        /// <summary>
        /// 删除空文件夹
        /// </summary>
        /// <param name="path"></param>
        private void DelEmptyFileFolder(string path)
        {
            DirectoryInfo folder = new DirectoryInfo(path);
            List<DirectoryInfo> lstDirInfo = new List<DirectoryInfo>();
            lstDirInfo = GetSubDirList(folder, lstDirInfo);

            if (lstDirInfo.Count > 0)
            {
                int fileCount = 0, dirCount = 0;
                for (int i = 0; i < lstDirInfo.Count; i++)
                {
                    DirectoryInfo dir_info = lstDirInfo[i];
                    fileCount = dir_info.GetFiles().Length;
                    dirCount = dir_info.GetDirectories().Length;
                    if (fileCount == 0 && dirCount == 0)//目录下即没有文件也没有子目录，则删除文件夹
                    {
                        try
                        {
                            Directory.Delete(lstDirInfo[i].FullName, true);

                            //lstDirInfo = GetSubDirList(folder, lstDirInfo);//只要删除了文件夹，则重新计算
                            //i = 0;
                        }
                        catch 
                        { }
                    }
                    else if (dirCount == 0)
                    {

                    }
                }
            }
        }

        /// <summary>
        /// 获取 指定目录下所有符合格式的FileInfo文件对象列表
        /// </summary>
        /// <param name="path">路径地址</param>
        /// <param name="fileFormat">文件后缀，比如 *.txt</param>
        /// <returns></returns>
        private List<FileInfo> GetDirFileList(string path, string fileFormat)
        {
            DirectoryInfo folder = new DirectoryInfo(path);
            List<FileInfo> lstFileInfo = new List<FileInfo>();
            lstFileInfo = GetSubDirFileList(folder, "*.txt", lstFileInfo);
            FileInfo[] arrFileInfo = folder.GetFiles("*.txt");
            foreach (FileInfo file in arrFileInfo)
            {
                lstFileInfo.Add(file);
            }
            return lstFileInfo;
        }

        /// <summary> 
        /// 获取指定目录de子目录下 所有符合文件后缀格式的文件信息对象（包括子目录）
        /// </summary> 
        /// <param name="theDir">指定目录</param> 
        /// <param name="fileFormat">文件后缀，比如 *.txt</param>
        /// <param name="lstFileInfo">用于迭加的传入值,一般为对象实例</param> 
        /// <returns></returns> 
        private List<FileInfo> GetSubDirFileList(DirectoryInfo theDir, string fileFormat, List<FileInfo> lstFileInfo)//递归目录 文件 
        {
            DirectoryInfo[] subDirectories = theDir.GetDirectories();//获得目录 
            foreach (DirectoryInfo dirinfo in subDirectories)
            {
                FileInfo[] fileInfo = dirinfo.GetFiles(); //目录下的文件 
                foreach (FileInfo fInfo in fileInfo)
                {
                    lstFileInfo.Add(fInfo);
                }
                lstFileInfo = GetSubDirFileList(dirinfo, fileFormat, lstFileInfo);
            }
            return lstFileInfo;
        }

        /// <summary>
        /// 获取 指定目录de子目录（包括子目录）
        /// </summary>
        /// <param name="theDir">指定目录</param>
        /// <param name="lstDirInfo">用于迭加的传入值,一般为对象实例用于迭加的传入值,一般为对象实例</param>
        /// <returns></returns>
        private List<DirectoryInfo> GetSubDirList(DirectoryInfo theDir, List<DirectoryInfo> lstDirInfo)
        {
            DirectoryInfo[] subDirectories = theDir.GetDirectories();//获得目录 
            foreach (DirectoryInfo dirinfo in subDirectories)
            {
                lstDirInfo.Add(dirinfo);
                lstDirInfo = GetSubDirList(dirinfo, lstDirInfo);
            }
            return lstDirInfo;
        }

        #endregion
    }
}
